package gui;
import javax.swing.*; 		 // For JPanel, etc.
import java.awt.*;           // For Graphics, etc.
import java.awt.geom.*;      // For Ellipse2D, etc.
import java.util.List;

import logic.Graph;
import logic.Tour;
import logic.Vertex;

/** An example of drawing/filling shapes with Java2D in Java 1.2.
 *
 *  From tutorial on learning Java2D at
 *  http://www.apl.jhu.edu/~hall/java/Java2D-Tutorial.html
 *
 *  1998 Marty Hall, http://www.apl.jhu.edu/~hall/java/
 */

public class GraphGUI extends JPanel {;
	int framelength = 30;
	int length = 550;
	int[] tour = null;
	Vertex[] vertices = null;
	Graph graph = null;
	boolean showpos = false;
	boolean showindices = false;
	
	public GraphGUI(Graph g, boolean showpositions, boolean showindices){
		if(showindices && showpositions){
			showpositions = false;
		}
		openWindow(g, showpositions, showindices);
	}
	
	public GraphGUI(Graph g, Tour tour, boolean showpositions, boolean showindices) {
		if(showindices && showpositions){
			showpositions = false;
		}
		addTour(tour.getTour());
		openWindow(g,showpositions, showindices);
	}
	
	public GraphGUI(Graph g, Tour tour, boolean showpositions, boolean showindices, String name) {
		if(showindices && showpositions){
			showpositions = false;
		}
		addTour(tour.getTour());
		openWindow(g,showpositions, showindices, name);
	}
	
	private void openWindow(Graph g, boolean showpositions, boolean showindices){
		this.graph = g;
		addVertices(g.vertices);
		this.showpos = showpositions;
		this.showindices = showindices;
		WindowUtilities.openInJFrame(this, length+2*framelength+35 ,
				length+2*framelength+60);
		
	}
	
	private void openWindow(Graph g, boolean showpositions, boolean showindices, String name){
		this.graph = g;
		addVertices(g.vertices);
		this.showpos = showpositions;
		this.showindices = showindices;
		WindowUtilities.openInJFrame(this, length+2*framelength+35 ,
				length+2*framelength+60);
		this.setToolTipText(name);
	}
	
	public void paintComponent(Graphics g) {
		int max = 0;
		int min = 0;
		double scale = 0;
		if(g!=null){
			max = getBiggest(graph);
			min = getSmallest(graph);

			int delta = max-min;
			scale = (((double)length)/((double)delta));
		}
		clear(g);
		Graphics2D g2d = (Graphics2D)g;
		
		if(g!=null){
			for(Vertex v : graph.vertices){
				double x = v.x-min;
				double y = v.y-min;
				g2d.fill(new Ellipse2D.Double(framelength+x*scale-3.5,framelength +length-(y*scale+3.5), 7, 7));
				if(showpos){
					String draw = "(" + getDoubleString(v.x) + "," + 
													getDoubleString(v.y)+")";
					g2d.drawString(draw, (int)(framelength + x * scale - 10) ,
							(int)(framelength  +length-( y * scale + 20)));
				} else if(showindices){
					String draw = ""+v.index;
					g2d.drawString(draw, (int)(framelength + x * scale - 10) ,
							(int)(framelength  +length-( y * scale + 20)));
				}
			}
			if(tour!=null){
				for(int i=0;i<tour.length; i++){
					double x1, x2, y1, y2;
					if(i == tour.length-1){
						x1 = vertices[tour[i]].x-min;
						y1 = vertices[tour[i]].y-min;
						x2 = vertices[tour[0]].x-min;
						y2 = vertices[tour[0]].y-min;
					} else {
						x1 = vertices[tour[i]].x-min;
						y1 = vertices[tour[i]].y-min;
						x2 = vertices[tour[i+1]].x-min;
						y2 = vertices[tour[i+1]].y-min;
					}
					g2d.draw(new Line2D.Double(framelength+x1*scale, framelength  +length-(y1*scale), 
							framelength+x2*scale, framelength  +length-(y2*scale)));
				}
			}
		}
//		g2d.draw(new Rectangle2D.Double(framelength, framelength, 
//				length+framelength , length+framelength));
	}
	
	public static String getDoubleString(double d){
		if(d==Math.round(d)){
			return Integer.toString((int)d);
		} else {
			return Double.toString(d);
		}
	}
	
	
	public void addVertices(Vertex[] vertices){
		this.vertices = vertices;
		this.paint(getGraphics());
	}
	
	public void addVertices(List<Vertex> vertices){
		this.vertices = new Vertex[vertices.size()];
		for(int i=0;i<vertices.size();i++){
			this.vertices[i] = vertices.get(i);
		}
		this.paint(getGraphics());
	}
	
	public void addTour(int[] tour){
		this.tour = tour;
		this.paint(getGraphics());
	}
	
	public void addTour(Vertex[] tour){
		this.tour = new int[tour.length];
		int index = 0;
		for(Vertex i : tour){
			this.tour[index] = i.index;
			index += 1;
		}
		this.paint(getGraphics());
	}
	
	public void addTour(List<Integer> tour){
		this.tour = new int[tour.size()];
		for(int i=0;i<tour.size();i++){
			this.tour[i] = tour.get(i);
		}
		this.paint(getGraphics());
		this.paint(getGraphics());
	}
	
	public void togglePositions(){
		if(showpos)
			showpos = false;
		else
			showpos = true;
	}
	
	private int getSmallest(Graph gr) {
		double smallest = Double.MAX_VALUE;
		for(Vertex v : gr.vertices){
			if(v.y < smallest){
				smallest = v.y;
			}
			if(v.x < smallest){
				smallest = v.x;
			}
		}
		return (int)(smallest);
	}

	private int getBiggest(Graph gr) {
		double biggest = Double.MIN_VALUE;
		for(Vertex v : gr.vertices){
			if(v.y > biggest){
				biggest = v.y;
			}
			if(v.x > biggest){
				biggest = v.x;
			}
		}
		return (int)(biggest);
	}
	
	// super.paintComponent clears offscreen pixmap,
	// since we're using double buffering by default.
	protected void clear(Graphics g) {
		super.paintComponent(g);
	}
}